﻿using System;
using System.Security.AccessControl;
using System.Text;

namespace TK
{
    public abstract class TypeHandler
    {
        internal abstract void Write(CustomSerializerState state, object o);
        internal abstract object Read(CustomSerializerState state);
    }

    class THBool:TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o) { state.stm.WriteByte((byte) ((bool) o ? 1 : 0)); }
        internal override object Read(CustomSerializerState state) { return state.stm.ReadByte() > 0; }
    }

    class THByte : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o) { state.stm.WriteByte((byte) o); }
        internal override object Read(CustomSerializerState state) { return (byte)state.stm.ReadByte(); }
    }

    class THSignedByte : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o) { state.stm.WriteByte((byte)(sbyte)o); }
        internal override object Read(CustomSerializerState state) { return (sbyte)state.stm.ReadByte(); }
    }

    class THInt16 : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o) { state.stm.Write(BitConverter.GetBytes((Int16)o), 0, 2); }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[2];
            state.stm.Read(b, 0, 2);
            return BitConverter.ToInt16(b, 0);
        }
    }

    class THUInt16 : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o) { state.stm.Write(BitConverter.GetBytes((UInt16)o), 0, 2); }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[sizeof(UInt16)];
            state.stm.Read(b, 0, b.Length);
            return BitConverter.ToUInt16(b, 0);
        }
    }

    class THInt32 : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o) { state.stm.Write(BitConverter.GetBytes((Int32)o), 0, sizeof(Int32)); }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[sizeof(Int32)];
            state.stm.Read(b, 0, b.Length);
            return BitConverter.ToInt32(b, 0);
        }
    }

    class THUInt32 : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o) { state.stm.Write(BitConverter.GetBytes((UInt32)o), 0, sizeof(UInt32)); }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[sizeof(UInt32)];
            state.stm.Read(b, 0, b.Length);
            return BitConverter.ToUInt32(b, 0);
        }
    }

    class THInt64 : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o) { state.stm.Write(BitConverter.GetBytes((Int64)o), 0, sizeof(Int64)); }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[sizeof(Int64)];
            state.stm.Read(b, 0, b.Length);
            return BitConverter.ToInt64(b, 0);
        }
    }

    class THUInt64 : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o) { state.stm.Write(BitConverter.GetBytes((UInt64)o), 0, sizeof(UInt64)); }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[sizeof(UInt64)];
            state.stm.Read(b, 0, b.Length);
            return BitConverter.ToUInt64(b, 0);
        }
    }

    class THSingle : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o) { state.stm.Write(BitConverter.GetBytes((Single)o), 0, sizeof(Single)); }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[sizeof(Single)];
            state.stm.Read(b, 0, b.Length);
            return BitConverter.ToSingle(b, 0);
        }
    }

    class THDouble : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o) { state.stm.Write(BitConverter.GetBytes((double)o), 0, sizeof(double)); }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[sizeof(double)];
            state.stm.Read(b, 0, b.Length);
            return BitConverter.ToDouble(b, 0);
        }
    }

    class THChar : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o) { state.stm.Write(BitConverter.GetBytes((char)o), 0, sizeof(char)); }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[sizeof(char)];
            state.stm.Read(b, 0, b.Length);
            return BitConverter.ToChar(b, 0);
        }
    }

    class THGuid : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o) { state.stm.Write(((Guid)o).ToByteArray(), 0, 16); }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[16];
            state.stm.Read(b, 0, b.Length);
            return new Guid(b);
        }
    }

    class THDecimal : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o)
        {
            var bits = Decimal.GetBits((Decimal)o);
            for (var i = 0; i < bits.Length; i++) // 4 * 32 bits = 128 bit
                state.stm.Write(BitConverter.GetBytes(bits[i]), 0, sizeof(int));
        }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[sizeof(int) * 4];  // 4 *4 int = 4 * 32 bits = 128 bit
            state.stm.Read(b, 0, b.Length);
            return new Decimal(
                new[]
                {
                    BitConverter.ToInt32(b, 0),
                    BitConverter.ToInt32(b, 4),
                    BitConverter.ToInt32(b, 8),
                    BitConverter.ToInt32(b, 12),
                });
        }
    }

    class THDateTime : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o)
        {
            var dt = (DateTime)o;
            state.stm.WriteByte((byte)(int)dt.Kind);
            var b = BitConverter.GetBytes(dt.Ticks);
            state.stm.Write(b, 0, b.Length);
        }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[8 + 1];
            state.stm.Read(b, 0, 8 + 1);

            return new DateTime(BitConverter.ToInt64(b, 1), (DateTimeKind)(int)b[0]);
        }
    }

    class THDateTimeOffset : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o)
        {
            var dto = (DateTimeOffset)o;

            var b = BitConverter.GetBytes(dto.Offset.Ticks);
            state.stm.Write(b, 0, b.Length);

            b = BitConverter.GetBytes(dto.Ticks);
            state.stm.Write(b, 0, b.Length);
        }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[8 + 8];
            state.stm.Read(b, 0, 8 + 8);
            var offs = BitConverter.ToInt64(b, 0);
            var value = BitConverter.ToInt64(b, 8);
            return new DateTimeOffset(value, TimeSpan.FromTicks(offs));
        }
    }

    class THTimeSpan : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o)
        {
            var b = BitConverter.GetBytes(((TimeSpan)o).Ticks);
            state.stm.Write(b, 0, b.Length);
        }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[8];
            state.stm.Read(b, 0, 8);
            return TimeSpan.FromTicks(BitConverter.ToInt64(b, 0));
        }
    }

    class THString : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o)
        {
            if (o == null) state.stm.Write(BitConverter.GetBytes(-1), 0, sizeof(Int32));
            else
            {
                var b = Encoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes((string) o));
                state.stm.Write(BitConverter.GetBytes(b.Length), 0, sizeof(Int32));
                state.stm.Write(b, 0, b.Length);
            }
        }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[sizeof(Int32)];
            state.stm.Read(b, 0, sizeof(Int32));
            var len = BitConverter.ToInt32(b, 0);
            if (len < 0) return null;
            b = new byte[len];
            state.stm.Read(b, 0, len);
            return Encoding.Default.GetString(Encoding.Convert(Encoding.UTF8, Encoding.Default, b));
        }
    }

    class THByteArray : TypeHandler
    {
        internal override void Write(CustomSerializerState state, object o)
        {
            if (o == null) state.stm.Write(BitConverter.GetBytes(-1), 0, sizeof(Int32));
            else
            {
                var b = (byte[]) o;
                state.stm.Write(BitConverter.GetBytes(b.Length), 0, sizeof(Int32));
                state.stm.Write(b, 0, b.Length);
            }
        }

        internal override object Read(CustomSerializerState state)
        {
            var b = new byte[sizeof(Int32)];
            state.stm.Read(b, 0, b.Length);
            var len = BitConverter.ToInt32(b, 0);
            if (len < 0) return null;

            b = new byte[len];
            state.stm.Read(b, 0, len);
            return b;
        }
    }
}